#include "../stdafx.h"
#include "../include/Platform.h"
#include "XPM.h"
#include "LineMarker.h"

namespace soy{

	void LineMarker::RefreshColourPalette(Palette &pal, bool want) {
		pal.WantFind(fore, want);
		pal.WantFind(back, want);
		pal.WantFind(backSelected, want);
		if (pxpm) {
			pxpm->RefreshColourPalette(pal, want);
		}
	}

	void LineMarker::SetXPM(const char *textForm) {
		delete pxpm;
		pxpm = new XPM(textForm);
		markType = SC_MARK_PIXMAP;
	}

	void LineMarker::SetXPM(const char *const *linesForm) {
		delete pxpm;
		pxpm = new XPM(linesForm);
		markType = SC_MARK_PIXMAP;
	}

	static void DrawBox(Surface *surface, int centreX, int centreY, int armSize, ColourAllocated fore, ColourAllocated back) {
		Rect rc;
		rc.left = centreX - armSize;
		rc.top = centreY - armSize;
		rc.right = centreX + armSize + 1;
		rc.bottom = centreY + armSize + 1;
		surface->RectangleDraw(rc, back, fore);
	}

	static void DrawCircle(Surface *surface, int centreX, int centreY, int armSize, ColourAllocated fore, ColourAllocated back) {
		Rect rcCircle;
		rcCircle.left = centreX - armSize;
		rcCircle.top = centreY - armSize;
		rcCircle.right = centreX + armSize + 1;
		rcCircle.bottom = centreY + armSize + 1;
		surface->Ellipse(rcCircle, back, fore);
	}

	static void DrawPlus(Surface *surface, int centreX, int centreY, int armSize, ColourAllocated fore) {
		Rect rcV(centreX, centreY - armSize + 2, centreX + 1, centreY + armSize - 2 + 1);
		surface->FillRectangle(rcV, fore);
		Rect rcH(centreX - armSize + 2, centreY, centreX + armSize - 2 + 1, centreY+1);
		surface->FillRectangle(rcH, fore);
	}

	static void DrawMinus(Surface *surface, int centreX, int centreY, int armSize, ColourAllocated fore) {
		Rect rcH(centreX - armSize + 2, centreY, centreX + armSize - 2 + 1, centreY+1);
		surface->FillRectangle(rcH, fore);
	}

	void LineMarker::Draw(Surface *surface, Rect &rcWhole, Font &fontForCharacter, typeOfFold tFold) {
		ColourPair head = back;
		ColourPair body = back;
		ColourPair tail = back;

		switch (tFold) {
	case LineMarker::head :
		head = backSelected;
		tail = backSelected;
		if (markType == SC_MARK_VLINE)
			body = backSelected;
		break;
	case LineMarker::body :
		head = backSelected;
		body = backSelected;
		break;
	case LineMarker::tail :
		body = backSelected;
		tail = backSelected;
		break;
	default :
		// LineMarker::undefined
		break;
		}


		if ((markType == SC_MARK_PIXMAP) && (pxpm)) {
			pxpm->Draw(surface, rcWhole);
			return;
		}
		// Restrict most shapes a bit
		Rect rc = rcWhole;
		rc.top++;
		rc.bottom--;
		int minDim = Platform::Minimum(rc.Width(), rc.Height());
		minDim--;	// Ensure does not go beyond edge
		int centreX = (rc.right + rc.left) / 2;
		int centreY = (rc.bottom + rc.top) / 2;
		int dimOn2 = minDim / 2;
		int dimOn4 = minDim / 4;
		int blobSize = dimOn2-1;
		int armSize = dimOn2-2;
		if (rc.Width() > (rc.Height() * 2)) {
			// Wide column is line number so move to left to try to avoid overlapping number
			centreX = rc.left + dimOn2 + 1;
		}
		if (markType == SC_MARK_ROUNDRECT) {
			Rect rcRounded = rc;
			rcRounded.left = rc.left + 1;
			rcRounded.right = rc.right - 1;
			surface->RoundedRectangle(rcRounded, fore.allocated, back.allocated);
		} else if (markType == SC_MARK_CIRCLE) {
			Rect rcCircle;
			rcCircle.left = centreX - dimOn2;
			rcCircle.top = centreY - dimOn2;
			rcCircle.right = centreX + dimOn2;
			rcCircle.bottom = centreY + dimOn2;
			surface->Ellipse(rcCircle, fore.allocated, back.allocated);
		} else if (markType == SC_MARK_ARROW) {
			Point pts[] = {
				Point(centreX - dimOn4, centreY - dimOn2),
				Point(centreX - dimOn4, centreY + dimOn2),
				Point(centreX + dimOn2 - dimOn4, centreY),
			};
			surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
				fore.allocated, back.allocated);

		} else if (markType == SC_MARK_ARROWDOWN) {
			Point pts[] = {
				Point(centreX - dimOn2, centreY - dimOn4),
				Point(centreX + dimOn2, centreY - dimOn4),
				Point(centreX, centreY + dimOn2 - dimOn4),
			};
			surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
				fore.allocated, back.allocated);

		} else if (markType == SC_MARK_PLUS) {
			Point pts[] = {
				Point(centreX - armSize, centreY - 1),
				Point(centreX - 1, centreY - 1),
				Point(centreX - 1, centreY - armSize),
				Point(centreX + 1, centreY - armSize),
				Point(centreX + 1, centreY - 1),
				Point(centreX + armSize, centreY -1),
				Point(centreX + armSize, centreY +1),
				Point(centreX + 1, centreY + 1),
				Point(centreX + 1, centreY + armSize),
				Point(centreX - 1, centreY + armSize),
				Point(centreX - 1, centreY + 1),
				Point(centreX - armSize, centreY + 1),
			};
			surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
				fore.allocated, back.allocated);

		} else if (markType == SC_MARK_MINUS) {
			Point pts[] = {
				Point(centreX - armSize, centreY - 1),
				Point(centreX + armSize, centreY -1),
				Point(centreX + armSize, centreY +1),
				Point(centreX - armSize, centreY + 1),
			};
			surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
				fore.allocated, back.allocated);

		} else if (markType == SC_MARK_SMALLRECT) {
			Rect rcSmall;
			rcSmall.left = rc.left + 1;
			rcSmall.top = rc.top + 2;
			rcSmall.right = rc.right - 1;
			rcSmall.bottom = rc.bottom - 2;
			surface->RectangleDraw(rcSmall, fore.allocated, back.allocated);

		} else if (markType == SC_MARK_EMPTY || markType == SC_MARK_BACKGROUND ||
			markType == SC_MARK_UNDERLINE || markType == SC_MARK_AVAILABLE) {
				// An invisible marker so don't draw anything

		} else if (markType == SC_MARK_VLINE) {
			surface->PenColour(body.allocated);
			surface->MoveTo(centreX, rcWhole.top + blobSize - (rcWhole.bottom - rcWhole.top)/2);
			surface->LineTo(centreX, rcWhole.bottom);

		} else if (markType == SC_MARK_LCORNER) {
			surface->PenColour(tail.allocated);
			surface->MoveTo(centreX, rcWhole.top);
			surface->LineTo(centreX, rc.top + dimOn2);
			surface->LineTo(rc.right - 2, rc.top + dimOn2);

		} else if (markType == SC_MARK_TCORNER) {
			surface->PenColour(tail.allocated);
			surface->MoveTo(centreX, rc.top + dimOn2);
			surface->LineTo(rc.right - 2, rc.top + dimOn2);

			surface->PenColour(body.allocated);
			surface->MoveTo(centreX, rcWhole.top);
			surface->LineTo(centreX, rc.top + dimOn2 + 1);

			surface->PenColour(head.allocated);
			surface->LineTo(centreX, rcWhole.bottom);

		} else if (markType == SC_MARK_LCORNERCURVE) {
			surface->PenColour(tail.allocated);
			surface->MoveTo(centreX, rcWhole.top);
			surface->LineTo(centreX, rc.top + dimOn2-3);
			surface->LineTo(centreX+3, rc.top + dimOn2);
			surface->LineTo(rc.right - 1, rc.top + dimOn2);

		} else if (markType == SC_MARK_TCORNERCURVE) {
			surface->PenColour(tail.allocated);
			surface->MoveTo(centreX, rc.top + dimOn2-3);
			surface->LineTo(centreX+3, rc.top + dimOn2);
			surface->LineTo(rc.right - 1, rc.top + dimOn2);

			surface->PenColour(body.allocated);
			surface->MoveTo(centreX, rcWhole.top);
			surface->LineTo(centreX, rc.top + dimOn2-2);

			surface->PenColour(head.allocated);
			surface->LineTo(centreX, rcWhole.bottom);

		} else if (markType == SC_MARK_BOXPLUS) {
			DrawBox(surface, centreX, centreY, blobSize, fore.allocated, head.allocated);
			DrawPlus(surface, centreX, centreY, blobSize, tail.allocated);

		} else if (markType == SC_MARK_BOXPLUSCONNECTED) {
			surface->PenColour(body.allocated);
			surface->MoveTo(centreX, centreY + blobSize);
			surface->LineTo(centreX, rcWhole.bottom);

			surface->PenColour(body.allocated);
			surface->MoveTo(centreX, rcWhole.top);
			surface->LineTo(centreX, centreY - blobSize);

			DrawBox(surface, centreX, centreY, blobSize, fore.allocated, head.allocated);
			DrawPlus(surface, centreX, centreY, blobSize, tail.allocated);

			if (tFold == LineMarker::body) {
				surface->PenColour(tail.allocated);
				surface->MoveTo(centreX + 1, centreY + blobSize);
				surface->LineTo(centreX + blobSize + 1, centreY + blobSize);

				surface->MoveTo(centreX + blobSize, centreY + blobSize);
				surface->LineTo(centreX + blobSize, centreY - blobSize);

				surface->MoveTo(centreX + 1, centreY - blobSize);
				surface->LineTo(centreX + blobSize + 1, centreY - blobSize);
			}
		} else if (markType == SC_MARK_BOXMINUS) {
			DrawBox(surface, centreX, centreY, blobSize, fore.allocated, head.allocated);
			DrawMinus(surface, centreX, centreY, blobSize, tail.allocated);

			surface->PenColour(head.allocated);
			surface->MoveTo(centreX, centreY + blobSize);
			surface->LineTo(centreX, rcWhole.bottom);

		} else if (markType == SC_MARK_BOXMINUSCONNECTED) {
			DrawBox(surface, centreX, centreY, blobSize, fore.allocated, head.allocated);
			DrawMinus(surface, centreX, centreY, blobSize, tail.allocated);

			surface->PenColour(head.allocated);
			surface->MoveTo(centreX, centreY + blobSize);
			surface->LineTo(centreX, rcWhole.bottom);

			surface->PenColour(body.allocated);
			surface->MoveTo(centreX, rcWhole.top);
			surface->LineTo(centreX, centreY - blobSize);

			if (tFold == LineMarker::body) {
				surface->PenColour(tail.allocated);
				surface->MoveTo(centreX + 1, centreY + blobSize);
				surface->LineTo(centreX + blobSize + 1, centreY + blobSize);

				surface->MoveTo(centreX + blobSize, centreY + blobSize);
				surface->LineTo(centreX + blobSize, centreY - blobSize);

				surface->MoveTo(centreX + 1, centreY - blobSize);
				surface->LineTo(centreX + blobSize + 1, centreY - blobSize);
			}
		} else if (markType == SC_MARK_CIRCLEPLUS) {
			DrawCircle(surface, centreX, centreY, blobSize, fore.allocated, head.allocated);
			DrawPlus(surface, centreX, centreY, blobSize, tail.allocated);

		} else if (markType == SC_MARK_CIRCLEPLUSCONNECTED) {
			surface->PenColour(body.allocated);
			surface->MoveTo(centreX, centreY + blobSize);
			surface->LineTo(centreX, rcWhole.bottom);

			surface->MoveTo(centreX, rcWhole.top);
			surface->LineTo(centreX, centreY - blobSize);

			DrawCircle(surface, centreX, centreY, blobSize, fore.allocated, head.allocated);
			DrawPlus(surface, centreX, centreY, blobSize, tail.allocated);

		} else if (markType == SC_MARK_CIRCLEMINUS) {
			DrawCircle(surface, centreX, centreY, blobSize, fore.allocated, head.allocated);
			DrawMinus(surface, centreX, centreY, blobSize, tail.allocated);

			surface->PenColour(head.allocated);
			surface->MoveTo(centreX, centreY + blobSize);
			surface->LineTo(centreX, rcWhole.bottom);

		} else if (markType == SC_MARK_CIRCLEMINUSCONNECTED) {
			DrawCircle(surface, centreX, centreY, blobSize, fore.allocated, head.allocated);
			DrawMinus(surface, centreX, centreY, blobSize, tail.allocated);

			surface->PenColour(head.allocated);
			surface->MoveTo(centreX, centreY + blobSize);
			surface->LineTo(centreX, rcWhole.bottom);

			surface->PenColour(body.allocated);
			surface->MoveTo(centreX, rcWhole.top);
			surface->LineTo(centreX, centreY - blobSize);

		} else if (markType >= SC_MARK_CHARACTER) {
			char character[1];
			character[0] = static_cast<char>(markType - SC_MARK_CHARACTER);
			int width = surface->WidthText(fontForCharacter, character, 1);
			rc.left += (rc.Width() - width) / 2;
			rc.right = rc.left + width;
			surface->DrawTextClipped(rc, fontForCharacter, rc.bottom - 2,
				character, 1, fore.allocated, back.allocated);

		} else if (markType == SC_MARK_DOTDOTDOT) {
			int right = centreX - 6;
			for (int b=0; b<3; b++) {
				Rect rcBlob(right, rc.bottom - 4, right + 2, rc.bottom-2);
				surface->FillRectangle(rcBlob, fore.allocated);
				right += 5;
			}
		} else if (markType == SC_MARK_ARROWS) {
			surface->PenColour(fore.allocated);
			int right = centreX - 2;
			for (int b=0; b<3; b++) {
				surface->MoveTo(right - 4, centreY - 4);
				surface->LineTo(right, centreY);
				surface->LineTo(right - 5, centreY + 5);
				right += 4;
			}
		} else if (markType == SC_MARK_SHORTARROW) {
			Point pts[] = {
				Point(centreX, centreY + dimOn2),
				Point(centreX + dimOn2, centreY),
				Point(centreX, centreY - dimOn2),
				Point(centreX, centreY - dimOn4),
				Point(centreX - dimOn4, centreY - dimOn4),
				Point(centreX - dimOn4, centreY + dimOn4),
				Point(centreX, centreY + dimOn4),
				Point(centreX, centreY + dimOn2),
			};
			surface->Polygon(pts, sizeof(pts) / sizeof(pts[0]),
				fore.allocated, back.allocated);
		} else if (markType == SC_MARK_LEFTRECT) {
			Rect rcLeft = rcWhole;
			rcLeft.right = rcLeft.left + 4;
			surface->FillRectangle(rcLeft, back.allocated);
		} else { // SC_MARK_FULLRECT
			surface->FillRectangle(rcWhole, back.allocated);
		}
	}


};
